options(scipen = 50);
require(strucchange);  # A dependency.
require(growthcurver); # A dependency.

plot.pdf <- function(x, height = 4, width = 4.5, pp = 8) {
    pdf(x, height = height, width = width, pointsize = pp);
}

if (exists(as.character(substitute(d))) == 0) {

    a <- read.csv("assert.csv", header = F);
    colnames(a) <- c("release",
                     "arch.files",
                     "arch.loc",
                     "arch.bug",
                     "arch.warn",
                     "block.files",
                     "block.loc",
                     "block.bug",
                     "block.warn",
                     "crypto.files",
                     "crypto.loc",
                     "crypto.bug",
                     "crypto.warn",
                     "drivers.files",
                     "drivers.loc",
                     "drivers.bug",
                     "drivers.warn",
                     "fs.files",
                     "fs.loc",
                     "fs.bug",
                     "fs.warn",
                     "kernel.files",
                     "kernel.loc",
                     "kernel.bug",
                     "kernel.warn",
                     "lib.files",
                     "lib.loc",
                     "lib.bug",
                     "lib.warn",
                     "net.files",
                     "net.loc",
                     "net.bug",
                     "net.warn",
                     "security.files",
                     "security.loc",
                     "security.bug",
                     "security.warn",
                     "sound.files",
                     "sound.loc",
                     "sound.bug",
                     "sound.warn",
                     "others.files",
                     "others.loc",
                     "others.bug",
                     "others.warn");

    if (1) {
        print(paste("files arch =", sum(a$arch.files)));
        print(paste("files block =", sum(a$block.files)));
        print(paste("files crypto =", sum(a$crypto.files)));
        print(paste("files drivers =", sum(a$drivers.files)));
        print(paste("files fs =", sum(a$fs.files)));
        print(paste("files kernel =", sum(a$kernel.files)));
        print(paste("files lib =", sum(a$lib.files)));
        print(paste("files net =", sum(a$net.files)));
        print(paste("files security =", sum(a$security.files)));
        print(paste("files sound =", sum(a$sound.files)));
        print(paste("files others =", sum(a$others.files)));
    }

    drop <- function(name) {
        idx <- which(colnames(a) == name);
        return(a[, -idx]);
    }

    a$others.files <- a$others.files + a$block.files;
    a$others.loc <- a$others.loc + a$block.loc;
    a$others.bug <- a$others.bug + a$block.bug;
    a$others.warn <- a$others.warn + a$block.warn;
    a <- drop("block.files"); a <- drop("block.loc");
    a <- drop("block.bug"); a <- drop("block.warn");

    a$others.files <- a$others.files + a$crypto.files;
    a$others.loc <- a$others.loc + a$crypto.loc;
    a$others.bug <- a$others.bug + a$crypto.bug;
    a$others.warn <- a$others.warn + a$crypto.warn;
    a <- drop("crypto.files"); a <- drop("crypto.loc");
    a <- drop("crypto.bug"); a <- drop("crypto.warn");

    a$others.files <- a$others.files + a$kernel.files;
    a$others.loc <- a$others.loc + a$kernel.loc;
    a$others.bug <- a$others.bug + a$kernel.bug;
    a$others.warn <- a$others.warn + a$kernel.warn;
    a <- drop("kernel.files"); a <- drop("kernel.loc");
    a <- drop("kernel.bug"); a <- drop("kernel.warn");

    a$others.files <- a$others.files + a$lib.files;
    a$others.loc <- a$others.loc + a$lib.loc;
    a$others.bug <- a$others.bug + a$lib.bug;
    a$others.warn <- a$others.warn + a$lib.warn;
    a <- drop("lib.files"); a <- drop("lib.loc");
    a <- drop("lib.bug"); a <- drop("lib.warn");

    a$others.files <- a$others.files + a$security.files;
    a$others.loc <- a$others.loc + a$security.loc;
    a$others.bug <- a$others.bug + a$security.bug;
    a$others.warn <- a$others.warn + a$security.warn;
    a <- drop("security.files"); a <- drop("security.loc");
    a <- drop("security.bug"); a <- drop("security.warn");

    if (1) {
        print(paste("files arch =", round(sum(a$arch.files) / nrow(a), 0)));
        print(paste("files drivers =", round(sum(a$drivers.files) / nrow(a), 0)));
        print(paste("files fs =", round(sum(a$fs.files) / nrow(a), 0)));
        print(paste("files net =", round(sum(a$net.files) / nrow(a), 0)));
        print(paste("files sound =", round(sum(a$sound.files) / nrow(a), 0)));
        print(paste("files others =", round(sum(a$others.files) / nrow(a), 0)));
        print(paste("loc arch =", round(sum(a$arch.loc) / nrow(a), 0)));
        print(paste("loc drivers =", round(sum(a$drivers.loc) / nrow(a), 0)));
        print(paste("loc fs =", round(sum(a$fs.loc) / nrow(a), 0)));
        print(paste("loc net =", round(sum(a$net.loc) / nrow(a), 0)));
        print(paste("loc sound =", round(sum(a$sound.loc) / nrow(a), 0)));
        print(paste("loc others =", round(sum(a$others.loc) / nrow(a), 0)));
    }

    a$release.v <- rep(NA, nrow(a));

    for (i in 1:nrow(a))
        a$release.v[i] <- gsub("linux-", "", a$release[i]);
}

plot.assertions <- function(eps) {

    if (eps != 0) {
        graphics.off();
        plot.pdf("fig_growth.pdf", 7, 16, 13);
    }

    par(mfrow = c(2, 3),
        mar = c(4, 5, 2, 5.5),
        font.main = 1, cex = 1);

    p <- function(main, warn, bug, sca, at.value) {

        lwd <- 2;

        plot(bug, type = "l",
             xaxt = "n", xlab = "", yaxt = "n", ylab = "",
             ylim = c(0, max(bug, warn, sca)),
             main = main, lwd = lwd, col = 2, cex.main = 1.3);

        lines(warn, col = 4, lwd = lwd);
        lines(sca, col = 1, lwd = lwd);

        mtext("Value", side = 2, line = 3.7, at = at.value);
        mtext("Release", side = 1, line = 2.5);
        axis(2, las = 2);
        axis(1, at = c(1, 37, 74), labels = c(a$release.v[1],
                                              a$release.v[37],
                                              a$release.v[74]));


        legend(par('usr')[2], par('usr')[4],
               c("FILE", "BUG", "WARN"), lwd = c(lwd, lwd, lwd),
               lty = c(1, 1, 1), col = c(1, 2, 4),
               cex = 1, xpd = NA, bty = "n");
    }

    p("arch", a$arch.warn, a$arch.bug, a$arch.files, 3000);
    p("drivers", a$drivers.warn, a$drivers.bug, a$drivers.files, 5000);
    p("fs", a$fs.warn, a$fs.bug, a$fs.files, 1500);
    p("net", a$net.warn, a$net.bug, a$net.files, 750);
    p("sound", a$sound.warn, a$sound.bug, a$sound.files, 750);
    p("others", a$others.warn, a$others.bug, a$others.files, 1500);

    if (eps != 0)
        graphics.off();
}

plot.cusums <- function(eps) {

    p.cusum <- function(z, subsystem, kol, b, title) {

        alpha <- 0.001;

        plot(z, col = kol, lwd = 2.5, alt.boundary = b,
             main = paste(subsystem, ": ", title, sep = ""),
             alpha = alpha, xlab = "", xaxt = "n");

        axis(1, at = c(0.1, 0.9),
             labels = c(a$release.v[1],
                        a$release.v[74]));

        mtext("Release", side = 1, line = 2);
        lines(boundary(z, alpha = alpha, alt.boundary = b), lwd = 1.5);
        lines(-boundary(z, alpha = alpha, alt.boundary = b), lwd = 1.5);
    }

    p <- function(subsystem, bug, warn, sca) {

        bug.1 <- bug;
        bug.2 <- bug / (bug + warn);
        bug.3 <- bug / sca;

        warn.1 <- warn;
        warn.2 <- warn / (bug + warn);
        warn.3 <- warn / sca;

        m <- matrix(nrow = 3, ncol = 2);
        colnames(m) <- c("y = BUG; x = WARN", "y = WARN; x = BUG");
        rownames(m) <- c("y", "y / (y + x)", "y / sca");

        c.bug.1 <- efp(bug.1 ~ 1, type = "OLS-CUSUM");
        c.bug.2 <- efp(bug.2 ~ 1, type = "OLS-CUSUM");
        c.bug.3 <- efp(bug.3 ~ 1, type = "OLS-CUSUM");

        c.warn.1 <- efp(warn.1 ~ 1, type = "OLS-CUSUM");
        c.warn.2 <- efp(warn.2 ~ 1, type = "OLS-CUSUM");
        c.warn.3 <- efp(warn.3 ~ 1, type = "OLS-CUSUM");

        # NB: gefp(y ~1, fit = lm) gives identical results
        #     for the g.bug.2 and g.bug.3 fits, as does efp().
        #
        g.bug.1 <- gefp(bug.1 ~ 1, fit = glm, family = poisson);
        g.bug.2 <- gefp(bug.2 ~ 1, fit = glm, family = gaussian);
        g.bug.3 <- gefp(bug.3 ~ 1, fit = glm, family = gaussian);

        g.warn.1 <- gefp(warn.1 ~ 1, fit = glm, family = poisson);
        g.warn.2 <- gefp(warn.2 ~ 1, fit = glm, family = gaussian);
        g.warn.3 <- gefp(warn.3 ~ 1, fit = glm, family = gaussian);

        p.cusum(c.bug.1, subsystem, 2, T, "BUG");
        p.cusum(c.warn.1, subsystem, 4, T, "WARN");

        m[1, 1] <- sctest(g.bug.1)$p.value;
        m[2, 1] <- sctest(g.bug.2)$p.value;
        m[3, 1] <- sctest(g.bug.3)$p.value;
        m[1, 2] <- sctest(g.warn.1)$p.value;
        m[2, 2] <- sctest(g.warn.2)$p.value;
        m[3, 2] <- sctest(g.warn.3)$p.value;

        print(subsystem);
        print(round(m, 5));
    }

    p.ar <- function(subsystem, bug, warn, sca) {

        d.bug <- diff(bug);
        bug.x <- cbind(d.bug[2:length(d.bug)], d.bug[1:(length(d.bug) - 1)]);
        bug.x <- as.data.frame(bug.x);
        colnames(bug.x) <- c("bug", "bug.lag");

        d.warn <- diff(warn);
        warn.x <- cbind(d.warn[2:length(d.warn)], d.warn[1:(length(d.warn) - 1)]);
        warn.x <- as.data.frame(warn.x);
        colnames(warn.x) <- c("warn", "warn.lag");

        bug.c <- efp(bug.x$bug ~ bug.x$bug.lag, dynamic = F, type = "OLS-CUSUM");
        warn.c <- efp(warn.x$warn ~ warn.x$warn.lag, dynamic = F, type = "OLS-CUSUM");

        r.bug <- lm(bug.x$bug ~ bug.x$bug.lag);
        r.warn <- lm(warn.x$warn ~ warn.x$warn.lag);

        p.cusum(bug.c, subsystem, 2, T, "BUG");
        p.cusum(warn.c, subsystem, 4, T, "WARN");

        print(paste(subsystem, ": BUG AR(1) coef. =", round(coef(r.bug)[2], 3)));
        print(paste(subsystem, ": WARN AR(1) coef. =", round(coef(r.warn)[2], 3)));
    }

    if (1) {

        if (eps != 0) {
            graphics.off();
            plot.pdf("fig_cusum.pdf", 7, 16, 13);
        }

        par(mfrow = c(2, 6),
            mar = c(4, 5, 2, 1),
            font.main = 1, cex = 1);

        p("arch", a$arch.bug, a$arch.warn, a$arch.files);
        p("drivers", a$drivers.bug, a$drivers.warn, a$drivers.files);
        p("fs", a$fs.bug, a$fs.warn, a$fs.files);
        p("net", a$net.bug, a$net.warn, a$net.files);
        p("sound", a$sound.bug, a$sound.warn, a$sound.files);
        p("others", a$others.bug, a$others.warn, a$others.files);

        if (eps != 0)
            graphics.off();
    }

    if (1) {

        if (eps != 0) {
            graphics.off();
            plot.pdf("fig_cusum_ar.pdf", 7, 16, 13);
        }

        par(mfrow = c(2, 6),
            mar = c(4, 5, 2, 1),
            font.main = 1, cex = 1);

        p.ar("arch", a$arch.bug, a$arch.warn, a$arch.files);
        p.ar("drivers", a$drivers.bug, a$drivers.warn, a$drivers.files);
        p.ar("fs", a$fs.bug, a$fs.warn, a$fs.files);
        p.ar("net", a$net.bug, a$net.warn, a$net.files);
        p.ar("sound", a$sound.bug, a$sound.warn, a$sound.files);
        p.ar("others", a$others.bug, a$others.warn, a$others.files);
    }

    if (eps != 0)
        graphics.off();
}

tab.logistic <- function() {

    t <- seq(1, nrow(a));
    m <- matrix(nrow = 6, ncol = 8);
    rownames(m) <- c("arch", "drivers", "fs", "net", "sound", "others");
    colnames(m) <- c("FILE b", "FILE b se", "LOC b", "LOC b se",
                     "BUG b", "BUG b se", "WARN b", "WARN b se");

    fit <- function(x) {
        r <- SummarizeGrowth(t, x);
        return(c(r$val$r, r$val$r_se));
    }

    m[1, 1:2] <- fit(a$arch.file);
    m[1, 3:4] <- fit(a$arch.loc);
    m[1, 5:6] <- fit(a$arch.bug);
    m[1, 7:8] <- fit(a$arch.warn);
    m[2, 1:2] <- fit(a$drivers.file);
    m[2, 3:4] <- fit(a$drivers.loc);
    m[2, 5:6] <- fit(a$drivers.bug);
    m[2, 7:8] <- fit(a$drivers.warn);
    m[3, 1:2] <- fit(a$fs.file);
    m[3, 3:4] <- fit(a$fs.loc);
    m[3, 5:6] <- fit(a$fs.bug);
    m[3, 7:8] <- fit(a$fs.warn);
    m[4, 1:2] <- fit(a$net.file);
    m[4, 3:4] <- fit(a$net.loc);
    m[4, 5:6] <- fit(a$net.bug);
    m[4, 7:8] <- fit(a$net.warn);
    m[5, 1:2] <- fit(a$sound.file);
    m[5, 3:4] <- fit(a$sound.loc);
    m[5, 5:6] <- fit(a$sound.bug);
    m[5, 7:8] <- fit(a$sound.warn);
    m[6, 1:2] <- fit(a$others.file);
    m[6, 3:4] <- fit(a$others.loc);
    m[6, 5:6] <- fit(a$others.bug);
    m[6, 7:8] <- fit(a$others.warn);

    print(round(m, 4));
}

eps <- 1;
plot.assertions(eps);
plot.cusums(eps);
tab.logistic();
